package com.cpp.server.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cpp.common.constant.redis.OperationConstant;
import com.cpp.common.constant.redis.RedisConstant;
import com.cpp.common.enums.AnswerStatus;
import com.cpp.common.enums.ExamStatus;
import com.cpp.common.enums.QuestionType;
import com.cpp.common.enums.UserRoleEnum;
import com.cpp.common.exception.BaseException;
import com.cpp.common.utils.ScoreAllocationUtils;
import com.cpp.pojo.dto.exam.AnswerDTO;
import com.cpp.pojo.dto.exam.ExamQuestionConfirmDTO;
import com.cpp.pojo.dto.question.QuestionGenerateDTO;
import com.cpp.pojo.pojo.*;
import com.cpp.pojo.vo.question.AnswerRightVO;
import com.cpp.pojo.vo.question.QuestionCreateConfirmVO;
import com.cpp.pojo.vo.question.QuestionExamVO;
import com.cpp.server.aspect.annotation.EndTimeRecord;
import com.cpp.server.aspect.annotation.UserRole;
import com.cpp.server.context.UserHolder;
import com.cpp.server.mapper.*;
import com.cpp.server.service.QuestionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
@RequiredArgsConstructor
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question> implements QuestionService {
    private final QuestionMapper questionMapper;
    private final ExamMapper examMapper;
    private final PracticeMapper practiceMapper;

    private final StringRedisTemplate redisTemplate;

    private final ExamServiceImpl examService;
    private final CourseMapper courseMapper;
    private final ChatClient gnerateQuestionChatClient;
    private final ChatClient studentPracticeChatClient;
    private final AnswerRecordMapper answerRecordMapper;


    @Override
    @Transactional
    @UserRole(roles = { UserRoleEnum.TEACHER})
    @EndTimeRecord(value = OperationConstant.generatePractice)
    public void updateQuestion(ExamQuestionConfirmDTO examQuestionConfirmDTO) {

        Exam exam = examMapper.selectById(examQuestionConfirmDTO.getExamId());
        exam.setStatus(1);

        examMapper.updateById(exam);
        //生成题目分数
        //0实训练习1开放题/2简答题/3单选题/4多选题
        QuestionType openQuestion = QuestionType.OPEN_QUESTION;//  开放题
        QuestionType shortQuestion = QuestionType.SHORT_ANSWER;// 简答题
        QuestionType singleQuestion = QuestionType.SINGLE_CHOICE;// 单选题
        QuestionType multipleQuestion = QuestionType.MULTIPLE_CHOICE;// 多选题

        Map<String, Integer> questionCountMap = new HashMap<>();
        questionCountMap.put(openQuestion.getName(), exam.getType1Count());
        questionCountMap.put(shortQuestion.getName(), exam.getType2Count());
        questionCountMap.put(singleQuestion.getName(), exam.getType3Count());
        questionCountMap.put(multipleQuestion.getName(), exam.getType4Count());

        // 题型权重
        Map<String, Double> weightMap = new HashMap<>();
        weightMap.put(openQuestion.getName(), openQuestion.getScoreWight());
        weightMap.put(shortQuestion.getName(), shortQuestion.getScoreWight());
        weightMap.put(singleQuestion.getName(), singleQuestion.getScoreWight());
        weightMap.put(multipleQuestion.getName(), multipleQuestion.getScoreWight());

        // 生成分数
        Map<String, List<Integer>> scoreDistribution = ScoreAllocationUtils.allocateScores(
                100, questionCountMap, weightMap);

        //获得所有分数
        List<Integer> open = scoreDistribution.get(openQuestion.getName());
        List<Integer> shor = scoreDistribution.get(shortQuestion.getName());
        List<Integer> single = scoreDistribution.get(singleQuestion.getName());
        List<Integer> multiple = scoreDistribution.get(multipleQuestion.getName());

        List<Question> questions = new ArrayList<>();
        for (ExamQuestionConfirmDTO.QuestionVO question : examQuestionConfirmDTO.getQuestions()) {
            Question build = Question.builder()
                    .id(question.getQuestionId())
                    .examId(examQuestionConfirmDTO.getExamId())
                    .knowledgeIds(question.getKnowledgeIds())
                    .courseId(exam.getCourseId())
                    .content(question.getContent())
                    .type(question.getType())
                    .answer(question.getAnswer())
                    .analysis(question.getAnalysis())
                    .difficulty(question.getDifficulty())
                    .build();
            questions.add(build);
        }
        questionMapper.updateById(questions);

        //通过考试id查询全部题目
        LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Question::getExamId,examQuestionConfirmDTO.getExamId());
        List<Question> questionList = questionMapper.selectList(queryWrapper);

        //根据题型为所有题目赋分
        for (Question question : questionList) {
            if (question.getType().equals(openQuestion.getType())) {
                question.setScore(open.get(0));
                open.remove(0);
            } else if (question.getType().equals(shortQuestion.getType())) {
                question.setScore(shor.get(0));
                shor.remove(0);
            } else if (question.getType().equals(singleQuestion.getType())) {
                question.setScore(single.get(0));
                single.remove(0);
            } else if (question.getType().equals(multipleQuestion.getType())) {
                question.setScore(multiple.get(0));
                multiple.remove(0);
            }
        }
        //更新考试状态
        exam.setStatus(ExamStatus.PUBLISHED.getCode());
        examMapper.updateById(exam);

        //批量更新
        questionMapper.updateById(questionList);

    }

    @Override
    @UserRole(roles = { UserRoleEnum.STUDENT})
    public List<QuestionExamVO> generateQuestion(QuestionGenerateDTO questionGenerateDTO) {
        User currentUser = UserHolder.getCurrentUser();

        LambdaQueryWrapper<Practice> queryWrapper = new LambdaQueryWrapper<>();
        //type不为0，考试id为0
        queryWrapper.eq(Practice::getUserId, currentUser.getId());
        queryWrapper.eq(Practice::getStatus, 0);//状态为0 未完成 1  完成

        List<Practice> practices = practiceMapper.selectList(queryWrapper);

//        if (practices.size()>=10){
//            throw new BaseException("题目数量已达上限,先去完成之前生成的题目吧");
//        }
        if (
                practices.size()+
                        questionGenerateDTO.getType1Count()+
                        questionGenerateDTO.getType2Count()+
                        questionGenerateDTO.getType3Count()+
                        questionGenerateDTO.getType4Count()>10
        ){
            throw new BaseException("题目数量总共不能超过十道,先去完成之前生成的题目吧");
        }
        //查询科目错题
        LambdaQueryWrapper<AnswerRecord> questionErrorWrapper = new LambdaQueryWrapper<>();
        questionErrorWrapper.eq(AnswerRecord::getUserId, currentUser.getId());
        questionErrorWrapper.eq(AnswerRecord::getSubjectId, questionGenerateDTO.getSubjectId());
        List<AnswerRecord> answerRecords = answerRecordMapper.selectList(questionErrorWrapper);

        //拼接提示词
        String string = "";
        for (AnswerRecord answerRecord : answerRecords) {
            string+= answerRecord.toString();
        }
        log.info("错题信息：{}", string);
        String content = studentPracticeChatClient.prompt()
                .user("结合错题信息，把生成的题目保存到数据库" +
//                        "错题信息"+string+
                        "学生id：" + currentUser.getId() +
                        "学科id：" + questionGenerateDTO.getSubjectId() +
                        "用户提示词：" + questionGenerateDTO.getPrompt() +
                        "生成" + QuestionType.OPEN_QUESTION.getName() + questionGenerateDTO.getType1Count() + "道" +
                        "生成" + QuestionType.SHORT_ANSWER.getName() + questionGenerateDTO.getType2Count() + "道" +
                        "生成" + QuestionType.SINGLE_CHOICE.getName() + questionGenerateDTO.getType3Count() + "道" +
                        "生成" + QuestionType.MULTIPLE_CHOICE.getName() + questionGenerateDTO.getType4Count() + "道"
                )
                .call()
                .content();
        log.info("ai生成题目：{}", content);
        String questionsJSON = redisTemplate.opsForValue().get(RedisConstant.STUDENT_PRACTICE_KEY + currentUser.getId());

        List<Question>  questions = JSON.parseArray(questionsJSON, Question.class);
        List<Practice> practices1 = BeanUtil.copyToList(questions, Practice.class);
//        给每个Practice插入当前用户id
        for (Practice practice : practices1) {
            practice.setUserId(currentUser.getId());
            practice.setSubjectId(questionGenerateDTO.getSubjectId());
        }

        practices.addAll(practices1);

        practiceMapper.insert(practices1);
        log.info("数据库中题目：{}", practices);
//        String questionJSON = redisTemplate.opsForValue().get(RedisConstant.STUDENT_PRACTICE_KEY);
//        List<Question> questions = JSON.parseArray(questionJSON, Question.class);

        //数据转换Practice-》QuestionVO
        List<QuestionExamVO> questionExamVOS = new ArrayList<>();
        for ( Practice practice : practices) {
            Integer type = practice.getType();
            if (type.equals(QuestionType.SINGLE_CHOICE.getType()) || type.equals(QuestionType.MULTIPLE_CHOICE.getType())) {
                QuestionExamVO questionExamVO = QuestionExamVO.builder()
                        .questionId(practice.getId())
                        .type(practice.getType())
                        .typeName(QuestionType.getType(practice.getType()).getName())
                        .content(practice.getContent())
                        .option(practice.getAnswer())
                        .build();
                questionExamVOS.add(questionExamVO);
            } else {
                QuestionExamVO questionExamVO = QuestionExamVO.builder()
                        .questionId(practice.getId())
                        .type(practice.getType())
                        .typeName(QuestionType.getType(practice.getType()).getName())
                        .content(practice.getContent())
                        .build();
                questionExamVOS.add(questionExamVO);
            }
        }
        return questionExamVOS;
    }

    @Override
    @UserRole(roles = { UserRoleEnum.STUDENT})
    public AnswerRightVO checkAnswer(AnswerDTO answer) {

        Practice practice = practiceMapper.selectById(answer.getQuestionId());
        User currentUser = UserHolder.getCurrentUser();

        if (practice==null){
            throw new BaseException("题目不存在");
        }
        Question question = BeanUtil.copyProperties(practice, Question.class);

        //判断正确与否
        boolean isRight = false;
        String message ="";
        //开放题
        if (practice.getType().equals(QuestionType.OPEN_QUESTION.getType())) {
            Double scoreRate = examService.judgeRightForOpenAndShort(question, answer);
            log.info("开放题：{}", scoreRate);
            isRight = scoreRate >= 0.6;
            if (scoreRate>=0.8&&scoreRate<=1){
                message = AnswerRightVO.MESSAGE_PERFECT;
            }
            else if (scoreRate>=0.6&&scoreRate<0.8){
                message = AnswerRightVO.MESSAGE_EXCELLENT;
            }
            else if (scoreRate>=0.4&&scoreRate<0.6){
                message = AnswerRightVO.MESSAGE_AVERAGE;
            }
            else if (scoreRate>=0&&scoreRate<0.4){
                message = AnswerRightVO.MESSAGE_WRONG;
            }
        }
        //简答题
        else if (practice.getType().equals(QuestionType.SHORT_ANSWER.getType())) {
            Double scoreRate = examService.judgeRightForOpenAndShort(question, answer);
            log.info("简答题：{}", scoreRate);
            isRight = scoreRate >= 0.6;
            if (scoreRate>=0.8&&scoreRate<=1){
                message = AnswerRightVO.MESSAGE_PERFECT;
            }
            else if (scoreRate>=0.6&&scoreRate<0.8){
                message = AnswerRightVO.MESSAGE_EXCELLENT;
            }
            else if (scoreRate>=0.4&&scoreRate<0.6){
                message = AnswerRightVO.MESSAGE_AVERAGE;
            }
            else if (scoreRate>=0&&scoreRate<0.4){
                message = AnswerRightVO.MESSAGE_WRONG;
            }
        }
        //单选题
        else if (practice.getType().equals(QuestionType.SINGLE_CHOICE.getType())) {
            if (examService.judgeRightForSingle(question, answer)) {
                isRight = true;
                message = AnswerRightVO.MESSAGE_PERFECT;
            } else {
                message = AnswerRightVO.MESSAGE_WRONG;
            }
        }
        //多选题
        else if (practice.getType().equals(QuestionType.MULTIPLE_CHOICE.getType())) {
            if (examService.judgeRightForMultiple(question, answer)) {
                isRight = true;
                message = AnswerRightVO.MESSAGE_PERFECT;
            } else {
                message = AnswerRightVO.MESSAGE_WRONG;
            }
        }

        if (!isRight){
            AnswerRecord answerRecord = AnswerRecord.builder()
                    .practiceId(answer.getQuestionId())
                    .userId(currentUser.getId())
                    .courseId(practice.getCourseId())
                    .type(practice.getType())
                    .content(practice.getContent())
                    .difficulty(practice.getDifficulty())
                    .knowledgeIds(practice.getKnowledgeIds())
                    .answer(practice.getAnswer())
                    .subjectId(practice.getSubjectId())
                    .userAnswer(answer.getAnswer())
                    .status(AnswerStatus.ERROR.getStatus())
                    .analysis(practice.getAnalysis())
                    .build();
            answerRecordMapper.insert(answerRecord);
        }else {
            AnswerRecord answerRecord = AnswerRecord.builder()
                    .practiceId(answer.getQuestionId())
                    .userId(currentUser.getId())
                    .courseId(practice.getCourseId())
                    .type(practice.getType())
                    .content(practice.getContent())
                    .difficulty(practice.getDifficulty())
                    .knowledgeIds(practice.getKnowledgeIds())
                    .answer(practice.getAnswer())
                    .subjectId(practice.getSubjectId())
                    .userAnswer(answer.getAnswer())
                    .status(AnswerStatus.RIGHT.getStatus())
                    .analysis(practice.getAnalysis())
                    .build();
            answerRecordMapper.insert(answerRecord);
        }
        //操作数据库，更新练习状态
        Practice build = Practice.builder()
                .id(answer.getQuestionId())
                .status(1)
                .build();
        practiceMapper.updateById(build);

        return AnswerRightVO.builder()
                .right(isRight ? 1 : 0)
                .message(message)
                .analysis(question.getAnalysis())
                .build();
    }

    @Override
    @UserRole(roles = { UserRoleEnum.STUDENT})
    public List<QuestionExamVO> listPractice() {
        User currentUser = UserHolder.getCurrentUser();

        LambdaQueryWrapper<Practice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Practice::getUserId, currentUser.getId());
        queryWrapper.eq(Practice::getStatus, 0);
        List<Practice> practices = practiceMapper.selectList(queryWrapper);

        List<QuestionExamVO> questionExamVOS =new ArrayList<>();
        for (Practice practice : practices) {
            Integer type = practice.getType();
            if (type.equals(QuestionType.SINGLE_CHOICE.getType()) || type.equals(QuestionType.MULTIPLE_CHOICE.getType())) {
                QuestionExamVO questionExamVO = QuestionExamVO.builder()
                        .questionId(practice.getId())
                        .type(practice.getType())
                        .typeName(QuestionType.getType(practice.getType()).getName())
                        .content(practice.getContent())
                        .option(practice.getAnswer())
                        .build();
                questionExamVOS.add(questionExamVO);
            } else {
                QuestionExamVO questionExamVO = QuestionExamVO.builder()
                        .questionId(practice.getId())
                        .type(practice.getType())
                        .typeName(QuestionType.getType(practice.getType()).getName())
                        .content(practice.getContent())
                        .build();
                questionExamVOS.add(questionExamVO);
            }
        }
        return questionExamVOS;
    }

    @Override
    @UserRole(roles = { UserRoleEnum.TEACHER})
    public QuestionCreateConfirmVO listExamQuestion(Long examId) {

        return null;
    }


}
